package com.xx.secret.core;

import com.google.common.collect.Maps;
import com.xx.secret.exception.SecretException;
import com.xx.secret.notify.INotifyProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * @author wangcheng
 * @date 2021/4/25
 */
@Component
@Slf4j
public class OpenContextProvider implements ApplicationContextAware , InitializingBean {

    private static Map<String, IOpenVerify> verifyStrategy = Maps.newConcurrentMap();

    private static Map<String, INotifyProcessor> notifyStrategy = Maps.newConcurrentMap();

    private static List<LoanOpenContext> clazzList = new ArrayList<>();

    static class LoanOpenContext{

        private String biz;

        private Map<String,? extends ApiLoan> clazz;

        public LoanOpenContext(String biz, Map<String, ? extends ApiLoan> clazz) {
            this.biz = biz;
            this.clazz = clazz;
        }

        public String getBiz() {
            return biz;
        }

        public Map<String, ? extends ApiLoan> getClazz() {
            return clazz;
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        Map<String, IOpenVerify> loanVerify = applicationContext.getBeansOfType(IOpenVerify.class);

        loanVerify.forEach((k,v)->verifyStrategy.put(v.getApiLoan().getApiName(),v));

        Map<String, INotifyProcessor> notifyBeansOfType = applicationContext.getBeansOfType(INotifyProcessor.class);

        notifyBeansOfType.forEach((k,v)->{
            v.registerNotifyUrl().forEach(url->notifyStrategy.put(v.getApiLoan().getApiName().concat("/").concat(url.toString()),v));
        });

    }

    public static <T>T getClazz(ClazzEnum clazz,String apiName,Class<T> t){

        for (LoanOpenContext loanOpenContext : clazzList) {
            if (loanOpenContext.getBiz().equals(clazz.name())){

                return (T)loanOpenContext.getClazz().get(apiName);

            }
        }
        return null;
    }

    public static IOpenVerify getLoanVerifyClazz(String loanName){
        IOpenVerify clazz = getClazz(ClazzEnum.OpenVerifyProcessor, loanName, IOpenVerify.class);
        if (clazz == null) {
            log.error("三方回调处理系统异常 验签执行器获取失败");
            throw new SecretException("回调系统错误");
        }
        return clazz;
    }

    public static INotifyProcessor getNotifyClazz(String loanName){
        INotifyProcessor clazz = getClazz(ClazzEnum.NotifyProcessor, loanName, INotifyProcessor.class);
        if (clazz == null) {
            log.error("三方回调处理系统异常 回调执行器获取失败");
            throw new SecretException("回调系统错误");
        }
        return clazz;
    }


    @Override
    public void afterPropertiesSet()  {
        clazzList.add(new LoanOpenContext(ClazzEnum.OpenVerifyProcessor.name(),verifyStrategy));
        clazzList.add(new LoanOpenContext(ClazzEnum.NotifyProcessor.name(),notifyStrategy));
    }

    public enum ClazzEnum{

        OpenVerifyProcessor,
        NotifyProcessor;
    }
}
